package com.jxb.demo.controller;

import com.jxb.demo.dao.UserMapper;
import com.jxb.demo.es.SearchService;
import com.jxb.demo.es.entity.OrderEntity;
import com.jxb.demo.es.param.SearchParam;
import com.jxb.demo.event.MsgEvent;
import com.jxb.demo.event.MsgPublisher;
import com.jxb.demo.model.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.context.request.async.WebAsyncTask;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

/**
 * @desc 异步任务处理
 * 1）servlet3.0
 * 2）DeferredResult
 * 3）Callable
 * 4）WebAsync
 */
@RestController
@RequestMapping("/demo")
public class DemoController {

    private static Logger logger = LoggerFactory.getLogger(DemoController.class);

    @Autowired
    private MsgPublisher msgPublisher;

    @Resource
    private UserMapper userMapper;

    @Resource
    private SearchService searchService;

    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private static final Map<String,SseEmitter> emitterMap = new HashMap<>();

    @RequestMapping(value = "/test",method = RequestMethod.GET)
    public Object testControl(){
        logger.info("#####DemoController.testControl####");
        Object result = "test is ok";
//        AirEntity entity = new AirEntity();
//        entity.setAirId(5690L);
//        entity.setAirCode("device-air-02");
//        entity.setAirDirection("风向-东北风");
//        entity.setAirMode("制冷");
//        entity.setAirStatus(1);
//        entity.setAirTemp(10.0);
//        airConditionMapper.insert(entity);
        User user = new User();
        user.setId(199L);
        user.setUserName("jiaxuebing");
        user.setUserAddr("山东省青岛市李沧区");
        userMapper.insert(user);
        User user2 = new User();
        user2.setId(226L);
        user2.setUserName("laowang");
        user2.setUserAddr("山东省青岛市崂山区");
        userMapper.insert(user2);

        return result;
    }

    /**
     * @desc 长轮询
     * @return
     */
    @GetMapping(value ="/testPolling")
    public DeferredResult testLongPolling(){
        logger.info("#####DemoController.testLongPolling####");
        DeferredResult<String> deferredResult = new DeferredResult<>(8000L);
        //超时处理
        deferredResult.onTimeout(new Runnable() {
            @Override
            public void run() {
                System.out.println("Time out");
                deferredResult.setErrorResult("service is time out");
            }
        });
        //处理完成
        deferredResult.onCompletion(new Runnable() {
            @Override
            public void run() {
                System.out.println("do complete");
            }
        });
        deferredResult.onError(e->{
            deferredResult.setErrorResult(e);
        });
        new Thread(new Runnable() {
            @Override
            public void run() {
                try{
                    Thread.sleep(5000);
                    deferredResult.setResult("are you doing  long polling");
                }catch (Exception e){

                }
            }
        }).start();

        return deferredResult;
    }

    @GetMapping(value = "/polling")
    public Callable<String> polling(){
        logger.info("#####DemoController.polling####====>START");
        logger.info("Thread:{}",Thread.currentThread().getName());
        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println(Thread.currentThread().getName());
                return "are you ok?";
            }
        };
        logger.info("#####DemoController.polling####====>END");
        return callable;
    }

    @GetMapping(value = "/asyncPolling")
    public WebAsyncTask<String> asyncPolling(){
        logger.info("#####DemoController.asyncPolling####====>START");
        logger.info("Thread:{}",Thread.currentThread().getName());
        //创建WebAsyncTask的异步任务，超时时间5s
        WebAsyncTask<String> asyncTask = new WebAsyncTask<>(5000L, new Callable<String>() {
            @Override
            public String call() throws Exception {
                logger.info("Thread:{}",Thread.currentThread().getName());
                return "invoke webasyncTask success";
            }
        });
        //超时处理
        asyncTask.onTimeout(new Callable<String>() {
            @Override
            public String call() throws Exception {
                return "timer is out";
            }
        });
        //完成后处理
        asyncTask.onCompletion(new Runnable() {
            @Override
            public void run() {
                logger.info("complete the task");
            }
        });
        //异常处理
        asyncTask.onError(new Callable<String>() {
            @Override
            public String call() throws Exception {
                return "error is";
            }
        });
        logger.info("#####DemoController.asyncPolling####====>END");
        return asyncTask;
    }

    /**
     * @desc sse异步服务启动
     * @return
     */
    @GetMapping(value = "/sseStart")
    public SseEmitter sseStart(String clientId){
        logger.info("#####DemoController.sseStart####====>START");
        SseEmitter sseEmitter = new SseEmitter(300*1000L);
        //可以使用线程池进行异步处理
        //异常处理
        sseEmitter.onError((e)->{
            try{
                emitterMap.remove(clientId);
                sseEmitter.send("sseEmitter is error");
                sseEmitter.complete();
            }catch (Exception ex){

            }
            logger.error("sseEmitter::ERROR:{}",e);
        });
        //超时处理
        sseEmitter.onTimeout(()->{
            try{
                emitterMap.remove(clientId);
                sseEmitter.send("time is out");
                sseEmitter.complete();
            }catch (Exception e){

            }
        });
        emitterMap.put(clientId,sseEmitter);
        logger.info("#####DemoController.sseStart####====>END");
        return sseEmitter;
    }

    /**
     * @desc sse异步服务发送数据
     * @return
     */
    @GetMapping(value = "/sseSend")
    public Object sseSend(String clientId){
        logger.info("#####DemoController.sseSend####====>START");
        Object result = "success";
        try{
            SseEmitter sseEmitter = emitterMap.get(clientId);
            sseEmitter.send("timestamp:"+System.currentTimeMillis());
        }catch (Exception e){
            logger.error("####[ERROR:{}]",e);
        }
        logger.info("#####DemoController.sseSend####====>END");
        return result;
    }

    /**
     * @desc 结束sse异步服务
     * @return
     */
    @GetMapping(value = "/sseEnd")
    public Object sseEnd(String clientId){
        logger.info("#####DemoController.sseEnd####====>START");
        Object result = "Success";
        SseEmitter sseEmitter = emitterMap.get(clientId);
        sseEmitter.complete();
        logger.info("#####DemoController.sseEnd####====>END");
        return result;
    }

    @GetMapping(value = "/testResponseBody")
    public StreamingResponseBody testResponseBody(){
        return new StreamingResponseBody() {
            @Override
            public void writeTo(OutputStream outputStream) throws IOException {

            }
        };
    }


    /**
     * @desc spring boot事件测试
     * @return
     */
    @GetMapping(value = "/testEvent")
    public Object testEvent(){
        logger.info("#####DemoController.testEvent####====>START");
        Object result = "Success";
        msgPublisher.pulishMsgEvent(new MsgEvent("abc","a01-09","woaini,china"));
        logger.info("#####DemoController.testEvent####====>END");
        return result;
    }

    /**
     * @desc 保存数据到es
     * @return
     */
    @PostMapping("/saveEs")
    public Object saveEs(@RequestBody OrderEntity orderEntity){
        logger.info("#####DemoController.saveEs####====>START");
        Object result = "Success";
        searchService.addEntity(orderEntity);
        logger.info("#####DemoController.saveEs####====>END");
        return result;
    }



}
